﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace Sofire.Data
{
    public partial class QueryEngineBase
    {
        internal NonQueryResult ExecuteNonQuery(DbConnection connection, DbTransaction transaction, ExecuteCommand command, bool autoClosed)
        {
            int resultValue = 0;
            Exception exception = null;
            DbCommand dbCommand = this.CreateCommand(connection, command);

            if(transaction != null) dbCommand.Transaction = transaction;

            command.Aborted = false;
            var userToken = this.OnExecuting(ExecuteType.NoQuery, command);
            try
            {
                if(connection.State == ConnectionState.Closed) connection.Open();
                resultValue = dbCommand.ExecuteNonQuery();
            }
            catch(Exception ex)
            {
                if(command.Aborted)
                {
                    exception = ExecuteAbortException.Instance;
                }
                else
                {
                    exception = ex;
                }
            }
            finally
            {
                if(autoClosed) connection.TryClose();
            }
            var r = new NonQueryResult();

            r.Initialization(this, dbCommand, resultValue, exception);

            this.OnExecuted(ExecuteType.NoQuery, r, command, userToken);

            return r;
        }

        internal MultiNonQueryResult ExecuteNonQuery(DbConnection connection, DbTransaction transaction, List<ExecuteCommand> commands, ExecuteCompletedHandler completed, bool autoClosed)
        {
            int result = 0, executeIndex = 0;
            Exception exception = null;
            DbCommand dbCommand = null;
            bool needAction = completed != null;

            var userToken = this.OnExecuting(ExecuteType.MultiNoQuery, commands);

            try
            {
                if(connection.State == ConnectionState.Closed)
                    connection.Open();

                foreach(var command in commands)
                {
                    dbCommand = this.CreateCommand(connection, command);
                    if(transaction != null) dbCommand.Transaction = transaction;
                    result += dbCommand.ExecuteNonQuery();
                    if(needAction && !completed(executeIndex, command))
                    {
                        throw ExecuteAbortException.Instance;
                    }
                    executeIndex++;
                }

                executeIndex = -1;
            }
            catch(Exception ex)
            {
                if(commands != null && commands.Count > 0 && commands[0].Aborted)
                {
                    exception = ExecuteAbortException.Instance;
                }
                else
                {
                    exception = ex;
                }
            }
            finally
            {
                if(autoClosed) connection.TryClose();
            }
            var r = new MultiNonQueryResult(executeIndex);

            r.Initialization(this, dbCommand, result, exception);

            this.OnExecuted(ExecuteType.MultiNoQuery, r, commands, userToken);

            return r;
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        public NonQueryResult ExecuteNonQuery(ExecuteCommand command)
        {
            return this.ExecuteNonQuery(this.CreateConnection(), null, command, true);
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public NonQueryResult ExecuteNonQuery(string commandText)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, params object[] parameters)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, object objectInstance)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }

        /// <summary>
        /// 批量执行查询，并返回受影响的总行数。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        public MultiNonQueryResult ExecuteNonQuery(List<ExecuteCommand> commands)
        {
            return this.ExecuteNonQuery(commands, null);
        }

        /// <summary>
        /// 批量执行查询，并返回受影响的总行数。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        /// <param name="completed">每当一个 <see cref="Sofire.Data.ExecuteCommand"/> 执行成功后，将会执行该方法。</param>
        public MultiNonQueryResult ExecuteNonQuery(List<ExecuteCommand> commands, ExecuteCompletedHandler completed)
        {
            return this.ExecuteNonQuery(this.CreateConnection(), null, commands, completed, true);
        }
    }

    public partial class QueryContext
    {
        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        public NonQueryResult ExecuteNonQuery(ExecuteCommand command)
        {
            return this.Engine.ExecuteNonQuery(this.Connection, this.Transaction, command, false);
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public NonQueryResult ExecuteNonQuery(string commandText)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, params object[] parameters)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回受影响的行数。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public NonQueryResult ExecuteNonQuery(string commandText, object objectInstance)
        {
            return this.ExecuteNonQuery(new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }

        /// <summary>
        /// 批量执行查询，并返回受影响的总行数。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        public MultiNonQueryResult ExecuteNonQuery(List<ExecuteCommand> commands)
        {
            return this.ExecuteNonQuery(commands, null);
        }

        /// <summary>
        /// 批量执行查询，并返回受影响的总行数。
        /// </summary>
        /// <param name="commands">执行查询的命令集合。</param>
        /// <param name="completed">每当一个 <see cref="Sofire.Data.ExecuteCommand"/> 执行成功后，将会执行该方法。</param>
        public MultiNonQueryResult ExecuteNonQuery(List<ExecuteCommand> commands, ExecuteCompletedHandler completed)
        {
            return this.Engine.ExecuteNonQuery(this.Connection, this.Transaction, commands, completed, false);
        }
    }
}